home *** CD-ROM | disk | FTP | other *** search
- /*
- * $Id: iopen.c,v 0.91 1994/02/20 00:53:07 zhao Pre-Release $
- *
- *. This file is part of BIT shareware package. After the two weeks of
- * free evaluation period, you are encouraged (required) to register
- * your copy for a small registration fee, which is $35 for personal use
- * and $50 for commercial, government and institutional use.
- *
- * Copyright(c) 1993, 1994 by T.C. Zhao.
- * All rights reserved.
- *
- * Permission to use, copy, and distribute this software in its entirety
- * for non-commercial purposes is hereby granted, provided that the
- * above shareware and copyright notices and this permission notice
- * appear in all copies and their documentation.
- *
- * This software may be modified for your own use, but modified versions
- * may not be distributed without prior consent of the author.
- *
- * This software is provided "as is" without expressed or implied
- * warranty of any kind.
- *
- *.
- *
- * Purpose:
- * Performs all image IOs.
- *
- * The opening routine reads MAXSIGL bytes from the image file
- * and then walks down the global identification table for matches
- * with all signatures if they exist and in case they don't, filename
- * extension will be used to guess the image format. In case of multiple
- * or conflicting matches, the driver will try to get the image
- * description (width, height etc) and only the succesful ones will
- * be used.
- */
-
- #if !defined(lint) && defined(F_ID)
- char *id_open = "$Id: iopen.c,v 0.91 1994/02/20 00:53:07 zhao Pre-Release $";
- #endif
-
- #include "bit.h"
- #include "extern.h"
-
- /************************************************************************
- * close an image stream.
- ************************************************************************/
- void
- close_image(IPTR im)
- {
- int status = 0;
- if (im && im->fp)
- {
- status = fclose(im->fp);
- im->fp = 0;
- }
- #ifdef MDEBUG
- if (status == EOF)
- {
- M_debug("CloseImage", "Bad close");
- }
- #endif
- }
-
- #define MAXCSIG 4 /* max. conflicting signatures */
-
- /***********************************************************************
- * check if an image is in a recognized format. Return index into the
- * global image structure. Multiple matches are permitted and the
- * description routine will try every one of them until a description
- * can be found or all matches are exhausted and in that case, the
- * routine returns an error code (-1).
- ***********************************************************************/
-
- static int no_bark; /* if complain if unknow image type */
-
- int
- check_signature(FILE * fp, int found[], const char *fn)
- {
- unsigned char signature[MAXSIGL + 1];
- int i, cfound, j;
- const IMG_IO *io;
- const char *tmp;
- const SIG *s;
-
- if (Badfread(signature, 1, MAXSIGL, fp))
- {
- if (!no_bark)
- Bark("ImageLoad", "%s", feof(fp) ? "Premature EOF" :
- "Bad read");
- fclose(fp);
- return -1;
- }
-
- for (i = cfound = 0, io = img_io; i < totalfmt; i++, io++)
- {
- s = io->sig;
- for (j = 0; j < MAXISIG; j++, s++)
- {
- if (s->len > 0)
- {
- if (memcmp(s->sig, signature, s->len) == 0)
- found[cfound++] = i;
- }
- else if (j == 0)
- {
- /*
- * no signature, check extensions. Do this only for
- * formats that truly do not have a signature, j==0.
- */
-
- if ((tmp = file_ext(fn)) != 0)
- if (memcmp(io->ext, tmp, strlen(io->ext)) == 0)
- found[cfound++] = i;
- }
- }
- }
- return cfound;
- }
-
- /*****************************************************************
- * Check is the given file, fn, is an image file we can view.
- * Will not produce warning messages of any kind.
- ****************************************************************/
- const char *
- is_image_file(const char *fn)
- {
- int cfound = 0, found[MAXCSIG];
- FILE *fp;
- const char *key = 0;
-
- no_bark = 1; /* shut up complaining */
-
- if ((fp = fn ? fopen(fn, "r") : 0))
- {
- cfound = check_signature(fp, found, fn);
- fclose(fp);
- }
-
- /* check if loadable */
- if (cfound > 0)
- {
- if (img_io[found[0]].load != 0)
- key = img_io[found[0]].key;
- }
- no_bark = 0;
-
- return key;
- }
-
- /*******************************************************************
- * Use the info check_image returned, img_desc tries to get the
- * description of the image, width, height, type, among others,
- * and fill the related field in image struct
- *******************************************************************/
- static int
- image_desc(IPTR im, int found[], int nf)
- {
- int i, ok;
- IMG_IO *io;
- long offset;
-
- if (!im || nf <= 0)
- return -1;
-
- /*
- * remembner where we are, note that we are not necessarily at the
- * begining of the file
- */
-
- offset = ftell(im->fp);
-
- /*
- * loop thru all matched signatures and terminate either a description is
- * found or all signatures are exhaused
- */
-
- for (i = ok = 0; !ok && i < nf; i++)
- {
- fseek(im->fp, offset, SEEK_SET);
- io = img_io + found[i];
-
- /* get some vital info about the image. */
-
- im->io = io;
- im->type = io->type;
- im->t2b = io->t2b;
-
- /* if no display function is defined, use the generic one */
-
- if (!io->display)
- im->io->display = Generic_display;
-
- /* get image description per instruction */
- im->key = im->io->key;
- im->info = im->io->info;
- ok = io->desc(im) == 0;
- }
- return ok;
- }
-
- /***************************************************************
- * Gloabl entry to get an image description from a stream.
- * Can't assume that we are at the begining of the file.
- * fn is for reporting purpose only.
- ***************************************************************/
-
- IPTR
- open_image_fp(FILE * fp, const char *fn)
- {
- int cfound, found[MAXCSIG];
- IPTR im = 0;
- long offset;
-
- /*
- * remember where we are. Before handing over the stream for description,
- * we must be at the same location within the file
- */
-
- offset = ftell(fp);
-
- if ((cfound = check_signature(fp, found, fn)) <= 0)
- {
- if (!no_bark)
- Bark("OpenImage", "%s -- Unknown image type", fn);
- fclose(fp);
- return 0;
- }
-
- if (!im)
- { /* get_mem_iptr never returns if failure */
- im = get_mem_imgptr();
- im->cmap = get_mem_cmap();
- }
-
- im->fp = fp;
-
- /* restore the position */
-
- if (fseek(im->fp, offset, SEEK_SET))
- {
- M_err("OpenImage", "Error seeking");
- }
-
-
- Strncpy(im->ifile, fn, TC_FL);
-
- if (image_desc(im, found, cfound) <= 0)
- {
- /*
- * unable to get description. If the format is writeonly, don't
- * bitch
- */
-
- if (im->io->load && !no_bark)
- {
- Bark("ImageOpen", "%s: Error getting %s info",
- fn, im->io->key);
- }
- close_image(im);
- free_image(im);
- im = 0;
- return 0;
- }
- return im;
- }
-
- /*************************************************************************
- * Do the same thing, but with a file
- *************************************************************************/
- IPTR
- open_image(const char *fn)
- {
- FILE *fp;
-
- #ifdef MDEBUG
- M_debug("ImgOpen", "Trying_%s_", fn);
- #endif
-
- return (fp = msg_fopen(fn, "r")) ? open_image_fp(fp, fn) : 0;
- }
-
-
- /*******************************************************************
- * Global entry to load an image.
- *
- * This routine does it all: given a filename, load_image will
- * fill every member of the image structure and return the image
- * structure. Bad load is detected by either null return or a zero
- * in the ok field of the structure
- *******************************************************************/
-
- IPTR
- load_image_fp(FILE * fp, const char *fn)
- {
- IPTR im = open_image_fp(fp, fn);
- int scans, err = 0;
- pc_t lut[PCMAX];
-
-
- if (!im || img_get_rastermem(im) < 0)
- {
- close_image(im);
- free_image(im);
- return 0;
- }
-
- /* in case fit_image_size is active */
- open_main_window(im);
-
- update_image_info(im);
-
- im->ok = (scans = im->io->load(im)) >= 0;
-
- if (!im->ok) /* can't load the darn thing */
- {
- close_image(im);
- free_image(im);
- end_busy();
- return 0;
- }
-
- if (scans != 0 && (im->h != scans))
- {
- err = 1;
-
- /* bitch only if more than one line bad */
- if ((im->h - scans) > 1)
- Bark("ImageLoad", "%s: Only gotten %d of %d lines",
- im->ifile, scans, im->h);
- }
-
-
- if (im->io->textsgf) /* load text only if image ok */
- {
- M_info("ImgOpen", "Trying sgfs and text", fn);
- load_text(im);
- load_sgf(im);
- }
-
- end_busy();
-
- /* close image only if there is no more */
- if (!im->more)
- close_image(im);
-
- if (im->t2b) /* convert scan so that it runs from bottom
- * to top */
- {
- M_info("ImgOpen", "flipping");
- (void) flip_mat(im->mraster, im->h, im->w, 'r', im->esize);
- im->t2b = 0;
- }
-
- /*
- * to minimize interferance with window manager, we swap colormaps
- * entries to force some of the colors to be static, i.e., having the
- * same index as the default system map
- */
-
- if (IS_CI(im))
- {
-
- /*
- * if an error occured, we must mask off bits higher than CMAPBITS
- * because some of the pixel may have random values. A possible
- * optimization here is to mask only the scan lines that are bad.
- * Another possibility is to use calloc throughout
- */
-
- M_info("ImgOpen", "Preserving");
-
- if (err)
- do_ci_mask(im->raster, im->h * im->w, im->cmap->colors - 1);
-
- if (preserve_wm_colors)
- img_preserve_wm_colors(im);
-
- /* find out the number of unique colors */
- cmap_ucolors(im->cmap, lut);
- }
-
- /* check for aspect ratio and correct it if need to */
- if (im->aspect != 1000 && im->aspect != 0)
- {
- int nw, nh;
- if (yes_no("Display", "Non-square pixel", "Correct ?", 0))
- {
- if (im->aspect > 1000)
- {
- nw = (im->w * im->aspect) / 1000;
- nh = im->h;
- }
- else
- {
- nh = (im->h * 1000) / im->aspect;
- nw = im->w;
- }
- img_scale(im, nh, nw, 1, 0, 0);
- }
- im->aspect = 1000;
- }
-
- M_info("ImgOpen", "Load %s",
- im && im->io && im->io->display ? "OK" : "Not Ok");
-
- return im;
- }
-
- IPTR
- load_image(const char *fn)
- {
- FILE *fp;
-
- return (fp = msg_fopen(fn, "r")) ? load_image_fp(fp, fn) : 0;
- }
-
-
- /******************************************************************
- * Write the image to disk using the function io->dump.
- *****************************************************************/
-
- int
- write_image(const IMG_IO * io, IPTR im, const char *fn)
- {
- int err = 0, swap = 0;
- ci_t tran[2];
-
- if (!(im->fp = msg_fopen(fn, "w")))
- return -1;
-
- /*
- * Due to wm_color preservation, B&W might've been swapped. Take care of
- * the swap: 1's are supposed to be black
- */
-
- if (IS_BW(im))
- {
- if ((swap = im->cmap->ct[0][0] == 0))
- {
- tran[0] = 1;
- tran[1] = 0;
- modify_all_ci(im->raster, im->w * im->h, tran);
- }
- }
-
- /*
- * check raster direction. No need to do this as the writing routine
- * always knows the raster is handed with (0,0) at lower-left corner
- */
- #if 0
- if (io->t2b != im->t2b)
- {
- set_matop_quiet(1);
- flip_matrix(im->mraster, im->h, im->w, 'r', im->esize);
- im->t2b = !im->t2b;
- }
- #endif
-
- /* if cmap, see if we can squeeze the image size */
-
- if (io->type == im->type && IS_CI(im))
- {
- squeeze_image(im);
- }
-
- /* final check to make sure everything is ok, quantize if necessary */
-
- if (io->type != im->type)
- {
- if (io->type == T_CMAP) /* need special handling */
- {
- err = io->ncols;
- set_quant_max_color(err <= 0 ? MAXCML : err);
- }
- err = img_convert_type(im, io->type);
- }
-
- if (!err && (err = io->dump(im) < 0))
- {
- Bark("WriteImage", "%s: Error writing", fn);
- }
-
-
- /*
- * write text and marking info only if the current format is capable of
- * handling it
- */
-
- if (!err && io->textsgf)
- {
- dump_text(im->fp);
- dump_sgf(im->fp);
- }
- close_image(im);
-
- /* swap again for correct display */
- if (swap)
- modify_all_ci(im->raster, im->w * im->h, tran);
- return err;
- }
-
- /******************************************************************
- * Handle multi-images
- *****************************************************************/
- int
- handle_multi_images(IPTR im)
- {
- int n = 0;
-
- do
- {
- im->io->inext(im, ++n);
- if (im->ok)
- {
- im->io->display(im, 0, 0);
- }
- }
- while (im->more);
-
- /* must close the image stream here */
- close_image(im);
- return 0;
- }
-
-
- /* utility function for fopen, print a message if failure */
- FILE *
- msg_fopen(const char *ofile, const char *mode)
- {
- FILE *fp = 0;
-
- if (!ofile || !*ofile)
- {
- Bark("Fopen", "Bad filname");
- return 0;
- }
- if (!(fp = fopen(ofile, mode)))
- Bark("Fopen", ofile);
- return fp;
- }
-